﻿using System.Text;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.X509;

namespace Devonline.Security;

/// <summary>
/// SM2 算法提供加解密的数据安全服务
/// </summary>
public class SM2SecurityService(SecuritySetting securitySetting) : AsymmetricSecurityService(securitySetting), IAsymmetricSecurityService, ISecurityService
{
    /// <summary>
    /// 获取 SM2 曲线参数, 使用推荐的椭圆曲线参数: sm2p256v1
    /// </summary>
    private readonly X9ECParameters _curve = ECNamedCurveTable.GetByName("sm2p256v1");
    private ECPrivateKeyParameters? _privateKey;
    private ECPublicKeyParameters? _publicKey;

    /// <summary>
    /// 使用公钥加密数据
    /// </summary>
    /// <param name="publicKey">加密用的公钥</param>
    /// <param name="data">待加密的数据</param>
    /// <returns>加密后的数据</returns>
    public override byte[] Encrypt(byte[] publicKey, byte[] data)
    {
        var ecpoint = _curve.Curve.DecodePoint(publicKey);
        var domain = new ECDomainParameters(_curve);
        var ecPublicKeyParameters = new ECPublicKeyParameters("EC", ecpoint, domain);
        var asymmetricKeyParameter = new ParametersWithRandom(ecPublicKeyParameters, new SecureRandom());

        // 创建SM2加密器
        var sm2Engine = new SM2Engine();
        sm2Engine.Init(true, asymmetricKeyParameter);

        //执行加密操作
        return sm2Engine.ProcessBlock(data, 0, data.Length);
    }
    /// <summary>
    /// 使用私钥解密数据
    /// </summary>
    /// <param name="privateKey">解密用的私钥</param>
    /// <param name="data">待解密的数据</param>
    /// <returns>解密后的数据</returns>
    public override byte[] Decrypt(byte[] privateKey, byte[] data)
    {
        var domain = new ECDomainParameters(_curve);
        var digit = new BigInteger(1, privateKey);
        var asymmetricKeyParameter = new ECPrivateKeyParameters(digit, domain);

        // 创建SM2加密器
        var sm2Engine = new SM2Engine();
        sm2Engine.Init(false, asymmetricKeyParameter);

        // 执行解密操作
        return sm2Engine.ProcessBlock(data, 0, data.Length);
    }

    public override Task<byte[]> EncryptAsync(byte[] data)
    {
        var asymmetricKeyParameter = new ParametersWithRandom(_publicKey, new SecureRandom());

        // 创建SM2加密器
        var sm2Engine = new SM2Engine();
        sm2Engine.Init(true, asymmetricKeyParameter);

        //执行加密操作
        var encrypted = sm2Engine.ProcessBlock(data, 0, data.Length);
        return Task.FromResult(encrypted);
    }
    public override Task<byte[]> DecryptAsync(byte[] data)
    {
        // 创建SM2加密器
        var sm2Engine = new SM2Engine();
        sm2Engine.Init(false, _privateKey);

        // 执行解密操作
        var decrypted = sm2Engine.ProcessBlock(data, 0, data.Length);
        return Task.FromResult(decrypted);
    }

    /// <summary>
    /// 使用SM3withSM2对数据进行签名
    /// </summary>
    public byte[] Sign(byte[] privateKey, byte[] data)
    {
        var signer = SignerUtilities.GetSigner("SM3withSM2");
        var asymmetricKey = PrivateKeyFactory.CreateKey(privateKey);
        signer.Init(true, asymmetricKey);
        signer.BlockUpdate(data, 0, data.Length);
        return signer.GenerateSignature();
    }

    /// <summary>
    /// 验证签名是否有效
    /// </summary>
    public bool VerifySignature(byte[] publicKey, byte[] data, byte[] signature)
    {
        var signer = SignerUtilities.GetSigner("SM3withSM2");
        var asymmetricKey = PublicKeyFactory.CreateKey(publicKey);
        signer.Init(false, asymmetricKey);
        signer.BlockUpdate(data, 0, data.Length);
        return signer.VerifySignature(signature);
    }

    /// <summary>
    /// 从 Base64 编码的字符串加载私钥
    /// </summary>
    private static AsymmetricKeyParameter LoadPrivateKeyFromBase64(string base64Key)
    {
        byte[] keyBytes = Convert.FromBase64String(base64Key);

        // 解密私钥（SM2 私钥通常是未加密的）
        return PrivateKeyFactory.CreateKey(keyBytes);
    }

    /// <summary>
    /// 从 Base64 编码的字符串加载公钥
    /// </summary>
    private static AsymmetricKeyParameter LoadPublicKeyFromBase64(string base64Key)
    {
        // 将 Base64 字符串解码为字节数组
        byte[] keyBytes = Convert.FromBase64String(base64Key);
        return PublicKeyFactory.CreateKey(keyBytes);
    }


    /// <summary>
    /// 生成密钥对
    /// </summary>
    /// <param name="privateKey">输出私钥</param>
    /// <param name="publicKey">输出公钥</param>
    /// <returns></returns>
    public override void Generate(out byte[] privateKey, out byte[] publicKey)
    {
        // 获取 SM2 曲线参数
        X9ECParameters curve = ECNamedCurveTable.GetByName("sm2p256v1");
        KeyGenerationParameters parameters = new ECKeyGenerationParameters(new ECDomainParameters(curve), new SecureRandom());

        // 创建 SM2 密钥对生成器
        ECKeyPairGenerator generator = new ECKeyPairGenerator();
        generator.Init(parameters);

        // 创建密钥对
        var keyPair = generator.GenerateKeyPair();

        // 私钥
        ECPrivateKeyParameters privateKeyParameters = (ECPrivateKeyParameters)keyPair.Private;
        privateKey = privateKeyParameters.D.ToByteArrayUnsigned();

        // 公钥
        ECPublicKeyParameters publicKeyParameters = (ECPublicKeyParameters)keyPair.Public;
        publicKey = publicKeyParameters.Q.GetEncoded();
    }
    /// <summary>
    /// 生成密钥对并保存到文件
    /// 如密钥文件名 www.xxx.com(或/cert/www.xxx.com.crt), generateMode == Both, 则生成
    /// www.xxx.com.crt(公私钥)
    /// www.xxx.com.pem(公钥)
    /// www.xxx.com.key(私钥)
    /// </summary>
    /// <param name="fileName">密钥文件名</param>
    /// <param name="generateMode">密钥生成方式</param>
    /// <returns></returns>
    public override Task GenerateAsync(string keyName, KeyGenerateMode generateMode = KeyGenerateMode.Both)
    {
        throw new NotImplementedException();
    }

    /// <summary>
    /// 从公钥和私钥数据导入密钥
    /// </summary>
    /// <param name="publicKey">公钥</param>
    /// <param name="privateKey">私钥</param>
    /// <returns></returns>
    public override void Import(byte[] publicKey, byte[]? privateKey = null)
    {
        var ecpoint = _curve.Curve.DecodePoint(publicKey);
        var domain = new ECDomainParameters(_curve);
        _publicKey = new ECPublicKeyParameters("EC", ecpoint, domain);

        if (privateKey is not null)
        {
            var digit = new BigInteger(1, privateKey);
            _privateKey = new ECPrivateKeyParameters(digit, domain);
        }
    }
    /// <summary>
    /// 从文件导入密钥
    /// </summary>
    /// <param name="fileName">密钥文件名</param>
    /// <returns></returns>
    public override async Task ImportAsync(string fileName)
    {
        var lines = await File.ReadAllLinesAsync(fileName);
        var certificateInfo = new StringBuilder();
        foreach (var line in lines)
        {
            if (!line.StartsWith("-----"))
            {
                certificateInfo.Append(line);
            }
        }

        byte[] decode = Convert.FromBase64String(certificateInfo.ToString());
        using var stream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
        var certificate = new X509CertificateParser().ReadCertificate(stream);
    }
}